#include <iostream>
#include <stdio.h>
#include <unistd.h>
//#include <mysql/mysql.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
using namespace std;

typedef struct _ADDR{
    struct in_addr ip;
    int port;
}ADDR;

#define BUF_SIZE 550
pid_t send_fork=0,recv_fork=0;
int p_arr[2],sd=0,sd_2=0,send_len=0,recv_len=0;
struct sockaddr_in addr,addr_2;
char send_buf[BUF_SIZE], recv_buf[BUF_SIZE];

socklen_t addr_len=sizeof(addr),cli_sock_len= sizeof(addr);

#define IP "139.199.209.80"
//#define IP "127.0.0.1"
#define PORT    5683
ADDR cli_addr[2];
#define LISTEN_PORT 9996

/*
void send_task(){

    struct sockaddr_in addr;
    addr.sin_port=htons(PORT);
    addr.sin_addr.s_addr=inet_addr(IP);
    addr.sin_family=AF_INET;
    socklen_t addr_len= sizeof(addr);

    for(;;){
        if(0>sendto(sd,"aaaaaa",strlen("aaaaaa"),0,(struct sockaddr*)&addr,addr_len)){
            printf("send failed\n");
            break;
        }
        while(1);
    }
}
*/
void recv_task(){
    int i=0;
    int sd_cli=0;
    struct sockaddr_in cli_sock;
    printf("create recv task\n");
    for(;;){
        /*
         * 第0次接收到对方外网地址，第1次接收到自身外网地址
         * cli_addr[0]=对方外网地址
         * cli_addr[1]=自身外网地址
        */
        if(0>(recv_len=recvfrom(sd,&cli_addr[i],sizeof(cli_addr[i]),0,(struct sockaddr*)&cli_sock,&cli_sock_len))){
            break;
        }
        printf("recv ip: %s, port: %d\n",inet_ntoa(cli_addr[i].ip),ntohs(cli_addr[i].port));
        ++i;
        if(i>=2) {
            close(sd);      //防止绑定该套接字的端口失败
            if (0 > (sd_cli = socket(AF_INET, SOCK_DGRAM, 0))) {
                cout << "create socket error" << endl;
                break;
            }
            struct sockaddr_in client;
            client.sin_family = AF_INET;
            client.sin_port = cli_addr[0].port;
            client.sin_addr = cli_addr[0].ip;

            /***********绑定发送端口 为提交时的端口 否则无法穿透***********/
            int flag=1;
            if(setsockopt(sd_cli,SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(int))<0){       //地址配置为重复使用
                perror("a setsockopt");
                return ;
            }
            struct sockaddr_in send_addr;
            send_addr.sin_family = AF_INET;
            send_addr.sin_port = cli_addr[1].port;
            if (0 > bind(sd_cli, (sockaddr *) &send_addr, sizeof(send_addr))) {
                printf("1 a bind error \r\n");
            }
            /******************************/

            if (0 > sendto(sd_cli, "aaaaa", strlen("aaaaa"), 0, (struct sockaddr *) &client, sizeof(client))) {
                printf("send failed\n");
            } else {
                printf("port: %d send to ip: %s, port: %d ok\n", ntohs(cli_addr[1].port),inet_ntoa(cli_addr[0].ip), ntohs(cli_addr[0].port));
            }

            i=0;

           // close(sd_cli);      //关闭套接字    ？会不会影响之前打好的洞？
//            int recv_sd;
//            if (0 > (recv_sd = socket(AF_INET, SOCK_DGRAM, 0))) {
//                cout << "create socket error" << endl;
//                break;
//            }
//            struct sockaddr_in recv_addr;
//            recv_addr.sin_family = AF_INET;
//            recv_addr.sin_port = cli_addr[1].port;
//            if (0 > bind(recv_sd, (sockaddr *) &recv_addr, sizeof(recv_addr))) {
//                printf("a bind error \r\n");
//            }
            for(;;){
                if(0>(recv_len=recvfrom(sd_cli,recv_buf,sizeof(recv_buf),0,(struct sockaddr*)&cli_sock,&cli_sock_len))){
                    break;
                }
                printf("recv data: %s\n",recv_buf);
            }
        }
    }
}

int main() {


    int t=0;
    pipe(p_arr);
    if(0>(sd=socket(AF_INET,SOCK_DGRAM,0))){
        cout<<"create socket error"<<endl;
        return -1;
    }
    recv_fork=fork();
    if(recv_fork==0){
        recv_task();
    }

    struct sockaddr_in addr;
    addr.sin_port=htons(PORT);
    addr.sin_addr.s_addr=inet_addr(IP);
    addr.sin_family=AF_INET;

//    int flag=1;
//    if(setsockopt(sd,SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(int))<0){       //地址配置为重复使用
//        perror("a setsockopt");
//    }
    if(0>sendto(sd,"aaaaa---->\n",strlen("aaaaa---->\n"),0,(struct sockaddr*)&addr,sizeof(addr))){
        printf("send failed\n");
    }
    close(sd);      //防止绑定该套接字的端口失败
//    if(0>(sd_2=socket(AF_INET,SOCK_DGRAM,0))){
//        cout<<"create socket error"<<endl;
//        return -1;
//    }

//    addr_2.sin_family=AF_INET;
//    //addr_2.sin_addr.s_addr=0;
//    addr_2.sin_port=htons(LISTEN_PORT);
//
//    if(0>bind(sd_2,(sockaddr*)&addr_2,sizeof(addr_2))) {
//        printf("bind error\r\n");       //错误
//        return -1;
//    }
    while(1);
#if 0
    for(;;){
        //memset(recv_buf,0,BUF_SIZE);
        if(0>(recv_len=recvfrom(sd,&cli_addr,sizeof(cli_addr),0,(struct sockaddr*)&cli_sock[t],&cli_sock_len))){
            break;
        }
        printf("recv ip: %s, port: %d\n",inet_ntoa(cli_addr.ip),ntohs(cli_addr.port));




        write(p_arr[1],(void*)&cli,(size_t)cli_len);

        for(int i=0;i<recv_len;i++){
            printf("%02x",recv_buf[i]);
        }
        printf("\n---->\r\n");


        t++;
        send_len=sprintf(&send_buf[0],"I receiveid %d data your sent: <%s>\n",t,recv_buf);
        sendto(sd,&send_buf,send_len,0,(struct sockaddr*)&cli,cli_len);
        if(0>recv_len)
            break;

    }
#endif
    close(sd);
    cout << "disconnect" <<endl;
    return 0;
}
